package dao

import (
	"github.com/astaxie/beego/orm"
	"github.com/pkg/errors"
	"github.com/spf13/cast"
	"nft-server/common"
	"nft-server/model"
	"nft-server/util"
	"time"
)

type OrderDao struct {
	BaseDao
}

type IOrderDao interface {
	SaveOrderInfo(Order *model.Order) error
	UpdateOrderInfo(Order *model.Order) error
	GetOrderByUserId(userId string) ([]*model.Order, error)
	GetOrderByUserIdAndStatus(userId string, orderStatus []string) ([]*model.Order, error)
	GetAndUpdateOverTimeOrder(userId string, nowTime time.Time) ([]*model.Order, error)
	GetOrderByThirdId(thirdPartyId string) (*model.Order, error)
	GetOrderByOrderId(orderId string) (*model.Order, error)
	GetOrderWithMultiUserId(userIds []int, page, pageSize int) (orders []*model.Order, size int, totalNum int, err error)
	GetAllOrderWithPage(query *common.OrderQueryReq, nowTime time.Time) (orders []*model.Order, size, totalNum int, err error)
}

func GetOrderDao() IOrderDao {
	dao := &OrderDao{}
	dao.Init()
	return dao
}
func (od *OrderDao) SaveOrderInfo(Order *model.Order) error {
	_, err := od.O.Insert(Order)
	if err != nil {
		return errors.Errorf("insert error: %v", err)
	}
	return nil
}
func (od *OrderDao) UpdateOrderInfo(Order *model.Order) error {
	_, err := od.O.Update(Order)
	if err != nil {
		return errors.Errorf("update error: %v", err)
	}
	return nil
}

//获取该用户底下的所有订单
func (od *OrderDao) GetOrderByUserId(userId string) ([]*model.Order, error) {
	var orders []*model.Order
	recode := od.O.QueryTable(&model.Order{}).Filter("user_id", userId)
	_, err := recode.All(&orders)
	if err != nil {
		return nil, errors.Errorf("query table error: %v", err)
	}
	return orders, nil
}

//获取该用户底下的指定状态的所有订单
func (od *OrderDao) GetOrderByUserIdAndStatus(userId string, orderStatus []string) ([]*model.Order, error) {
	var orders []*model.Order
	recode := od.O.QueryTable(&model.Order{}).Filter("user_id", userId).Filter("order_status__in", orderStatus)
	_, err := recode.All(&orders)
	if err != nil {
		return nil, errors.Errorf("query table error: %v", err)
	}
	return orders, nil
}

//超时未支付订单
func (od *OrderDao) GetAndUpdateOverTimeOrder(userId string, nowTime time.Time) ([]*model.Order, error) {
	var orders []*model.Order
	recode := od.O.QueryTable(&model.Order{})
	condition := orm.NewCondition()
	finalCondition := orm.NewCondition()
	if len(userId) > 0 {
		finalCondition = condition.And("user_id", userId).And("order_status", util.TradeNoPay).And("expire_time__lt", nowTime)
	} else {
		finalCondition = condition.And("order_status", util.TradeNoPay).And("expire_time__lt", nowTime)
	}
	recode = recode.SetCond(finalCondition)
	_, err := recode.All(&orders)
	_, err = recode.Update(orm.Params{"order_status": util.TradeClosed})
	if err != nil {
		return nil, errors.Errorf("query table error: %v", err)
	}
	return orders, nil
}

//根据第三方订单ID查询
func (od *OrderDao) GetOrderByThirdId(thirdPartyId string) (*model.Order, error) {
	order := model.Order{}
	err := od.O.QueryTable(&model.Order{}).Filter("user_id", thirdPartyId).One(&order)
	if err != nil {
		return nil, errors.Errorf("read error: %v", err)
	}
	return &order, nil
}

//根据内部orderId查询订单
func (od *OrderDao) GetOrderByOrderId(orderId string) (*model.Order, error) {
	order := model.Order{}
	err := od.O.QueryTable(&model.Order{}).Filter("order_id", orderId).One(&order)
	if err != nil {
		return nil, errors.Errorf("get error: %v", err)
	}
	return &order, nil
}

//根据用户名查找当前订单
func (od *OrderDao) GetOrderWithMultiUserId(userIds []int, page, pageSize int) (orders []*model.Order, size int, totalNum int, err error) {
	var order []*model.Order
	offset := page - 1
	if page-1 < 0 {
		offset = 0
	}
	offset = offset * pageSize
	recode := od.O.QueryTable(&model.Order{})
	//筛选条件--增加模糊搜索
	recode = recode.Filter("user_id__contains", userIds)

	arrayNum, err := recode.Count()
	_, err = recode.Offset(offset).Limit(pageSize).All(&order)
	if err != nil {
		return nil, -1, -1, errors.Errorf("query table error: %v", err)
	}
	size = len(order)
	totalNum = cast.ToInt(arrayNum)
	return order, size, totalNum, nil
}

//查找所有用户订单
func (od *OrderDao) GetAllOrderWithPage(query *common.OrderQueryReq, nowTime time.Time) (orders []*model.Order, size, totalNum int, err error) {
	offset := query.Page - 1
	if query.Page-1 < 0 {
		offset = 0
	}
	offset = offset * query.PageSize
	recode := od.O.QueryTable(&model.Order{})
	//筛选条件设置
	finalCondition := buildConditionForGetAllOrderWithPage(query, nowTime)
	recode = recode.SetCond(finalCondition)
	arrayNum, err := recode.Count()
	_, err = recode.Offset(offset).Limit(query.PageSize).All(&orders)
	if err != nil {
		return nil, -1, -1, errors.Errorf("query table error: %v", err)
	}
	size = len(orders)
	totalNum = cast.ToInt(arrayNum)
	return orders, size, totalNum, nil
}

func buildConditionForGetAllOrderWithPage(query *common.OrderQueryReq, nowTime time.Time) *orm.Condition {
	condition := orm.NewCondition()
	statusCondition := orm.NewCondition()
	timeCondition := orm.NewCondition()
	identityCondition := orm.NewCondition()
	finalCondition := orm.NewCondition()
	CollectionIndexCondition := orm.NewCondition()
	if len(query.Role) > 0 {
		identityCondition = condition.And("user_id", query.UserId)
	}
	if len(query.CollectionIndex) > 0 {
		CollectionIndexCondition = condition.And("collectionIndex__in", query.CollectionIndex)
	}
	if len(query.OrderStatus) > 0 {
		statusCondition = condition.And("order_status__in", query.OrderStatus)
	}
	queryTime := nowTime
	if query.TimeRange != util.InAllTime {
		if query.TimeRange == util.InLastOneWeek {
			queryTime = nowTime.AddDate(0, 0, -7)
		} else if query.TimeRange == util.InLastThreeMonths {
			queryTime = nowTime.AddDate(0, -3, 0)
		} else if query.TimeRange == util.InLastSixMonths {
			queryTime = nowTime.AddDate(0, -6, 0)
		}
	}
	if queryTime.Before(nowTime) == true {
		timeCondition = condition.And("created_time__gt", queryTime).And("created_time__lt", nowTime)
	}
	if identityCondition.IsEmpty() == false {
		finalCondition = finalCondition.AndCond(identityCondition)
	}
	if timeCondition.IsEmpty() == false {
		finalCondition = finalCondition.AndCond(timeCondition)
	}
	if statusCondition.IsEmpty() == false {
		finalCondition = finalCondition.AndCond(statusCondition)
	}
	if CollectionIndexCondition.IsEmpty() == false {
		finalCondition = finalCondition.AndCond(CollectionIndexCondition)
	}
	return finalCondition
}
